package com.open.fei.filter;

import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR;

import com.open.fei.entities.ResponseObject;
import java.nio.charset.StandardCharsets;

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang.StringUtils;
import org.reactivestreams.Publisher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

/**
 * 响应过滤器
 */
@Component
public class ResponseGlobalFilter implements GlobalFilter, Ordered {
    private final Logger log = LoggerFactory.getLogger(ResponseGlobalFilter.class);

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 获取响应对象
        ServerHttpResponse response = exchange.getResponse();
        DataBufferFactory bufferFactory = response.bufferFactory();
        ServerHttpResponseDecorator responseDecorator = new ServerHttpResponseDecorator(response) {
            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                // 记录响应日志
                long end = System.currentTimeMillis();
                long start = Long.parseLong(exchange.getAttribute("start").toString());
                long useTime = end - start;

                if (body instanceof Flux) {
                    // 获取响应 ContentType
                    String responseContentType = exchange.getAttribute(ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR);
                    // 记录 JSON 格式数据的响应体
                    if (!StringUtils.isEmpty(responseContentType) && responseContentType.contains(MediaType.APPLICATION_JSON_VALUE)) {
                        Flux<? extends DataBuffer> fluxBody = Flux.from(body);
                        // 解决返回体分段传输
                        return super.writeWith(fluxBody.buffer().flatMap(dataBuffers -> {
                            DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
                            DataBuffer join = dataBufferFactory.join(dataBuffers);
                            byte[] content = new byte[join.readableByteCount()];
                            join.read(content);
                            DataBufferUtils.release(join);
                            String responseData = new String(content, StandardCharsets.UTF_8);

                            try {
                                // 将服务返回的json转为标准格式
                                ResponseObject object = JSON.parseObject(responseData, ResponseObject.class);
                                // 解析为object非200抛出异常
                                if (object.getData() != null && object.getCode() != 200 && !(boolean) object.getData()) {
                                    throw new RuntimeException(object.getMsg());
                                }

                                String responseStr = responseData.replaceAll("\n", "").replaceAll("\t", "");
                                responseStr = responseStr.length() > 500 ? responseStr.substring(0, 500) : responseStr;

                                log.info("=>> END: Time: {}ms", useTime);
                                log.info("RESPONSE INFO = {}", responseStr);

                                return Mono.just(bufferFactory.wrap(responseData.getBytes()));
                            } catch (Exception e) {
                                log.error("Error processing response data", e);
                                // 创建一个包含错误信息的响应体
                                String errorResponse = "{\"error\":\"" + e.getMessage() + "\"}";
                                DataBuffer errorBuffer = bufferFactory.wrap(errorResponse.getBytes(StandardCharsets.UTF_8));
                                return Mono.just(errorBuffer);
                            }
                        }));
                    }
                }

                return super.writeWith(body);
            }
        };

        return chain.filter(exchange.mutate().response(responseDecorator).build());
    }

    @Override
    public int getOrder() {
        return -2;
    }
}
